package com.bclz.state


trait RNG {
  def nextInt: (Int, RNG) // Should generate a random `Int`. We'll later define other functions in terms of `nextInt`.
}

case class Simple(seed: Long) extends RNG {
  override def nextInt: (Int, RNG) = {
    //281474976710655(0xFFFFFFFFFFFFL) = 2^48-1
    val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL // `&` is bitwise AND. We use the current seed to generate a new seed.
    val nextRNG = Simple(newSeed) // The next state, which is an `RNG` instance created from the new seed.
    val n = (newSeed >>> 16).toInt // `>>>` is right binary shift with zero fill. The value `n` is our new pseudo-random integer.
    (n, nextRNG) // The return value is a tuple containing both a pseudo-random integer and the next `RNG` state.

  }

}

object RNG  extends App {

  type Rand[+A] = RNG=>(A,RNG)

  def unit[A](a: A):Rand[A]=rng=>(a,rng)

  def map[A,B](s:Rand[A])(f:A=>B):Rand[B]=
    rng=>{
      val (a,rng2) = s(rng)
      (f(a),rng2)
    }

  def map[A,B,C](s1:Rand[A],s2:Rand[B])(f:(A,B)=>C):Rand[C]=
    rng=>{
      val (a,rng2)=s1(rng)
      val (b,rng3)=s2(rng2)
      (f(a,b),rng3)
    }

  /**状态传递**/
  def nonNegativeInt(rng:RNG):(Int,RNG)={

        val (intValue,state) = rng.nextInt
        if(intValue < 0) (Math.abs(intValue+1),state) else (intValue,state)
  }

  def double(rng:RNG):(Double,RNG)={
    val (intValue,state) = nonNegativeInt(rng)
    (intValue/(Integer.MAX_VALUE.toDouble+1),state)
  }

  def intDouble(rng:RNG):((Int,Double),RNG)={
    val (intValue,state)=rng.nextInt
    val (doubleValue,state2)=double(state)
    ((intValue,doubleValue),state2)
  }

  def doubleInt(rng: RNG):((Double,Int),RNG)={
    val ((intValue,doubleValue),state) = intDouble(rng)
    ((doubleValue,intValue),state)
  }

  def double3(rng:RNG):((Double,Double,Double),RNG)={
    val (doubleValue,state)=double(rng)
    val (doubleValue2,state2)=double(state)
    val (doubleValue3,state3)=double(state2)
    ((doubleValue,doubleValue2,doubleValue3),state3)
  }

  def ints(count:Int)(rng: RNG):List[Int]={
      if(count==0) Nil
      else{
        val (intV,state) = rng.nextInt
        intV::ints(count-1)(state)
      }
  }

  /**状态转换实现**/
  def nonNegativeEvent(rng:RNG):Rand[Int]=
    map(nonNegativeInt)(i=>i-i%2)

  def doubleViaMap(rng:RNG):(Double,RNG)=
    map(nonNegativeInt)(i=>i/(Int.MaxValue.toDouble +1))(rng)
}